﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using GMap.NET.WindowsPresentation;
using System.Windows.Media.Animation;
using GMap.NET;
using System.Windows.Media.Effects;
using System.Net;

namespace InteractiveMapApp.CustomMarkers
{
    /// <summary>
    /// Interaction logic for CustomMarker.xaml
    /// </summary>
    public partial class CustomMarker// : UserControl
    {
        public GMapMarker Marker;
        MainWindow MainWindow;
        ImageSource categorySource;
        ImageSource timeslotSource;
        public bool thisMarkersPopupIsShowing = false;
        public long storyID;

        System.Windows.Forms.Timer storyBubbleLifeTimer;
        DoubleAnimation scale = new DoubleAnimation();
        DoubleAnimation anim = new DoubleAnimation();
        DropShadowEffect shadowEffect;
        ScaleTransform oTransform;
        public bool isItACurrentUserStory;
        public bool reported;
        public bool showThisBubbleWhenCreating;
        bool animate;
        string storytext;
        string storytitle;
        string catdesc;
        string museumImageURL;
        Image museumImage;

        /// <summary>
        /// Instantiates the markers that are pinned on the main map canvas
        /// </summary>
        /// <param name="window">reference to the main window</param>
        /// <param name="marker">reference to the actual marker</param>
        /// <param name="categoryMarkerImage">the image for the custom marker(pin)</param>
        /// <param name="categoryIconImage">the image of the category</param>
        /// <param name="timeSlotIconImage">the image of the timeslot</param>
        /// <param name="storyText">the text of the story</param>
        /// <param name="storiesID">the id of the story</param>
        /// <param name="showBubbleOnCreation">true to display the bubble when it is added to the map</param>
        /// <param name="isItUserStory">true if the story is to be considered special as a user story</param>
        public CustomMarker(MainWindow window, GMapMarker marker, ImageSource categoryMarkerImage, ImageSource categoryIconImage, ImageSource timeSlotIconImage, string museumImageUrl, string storyText, string storyTitle, string catDesc, long storiesID, bool showBubbleOnCreation, bool isItUserStory, bool animateMarkerAppearance)
        {
            this.storyID = storiesID;
            this.InitializeComponent();
            this.MainWindow = window;
            this.Marker = marker;
            this.AllowDrop = false;
            this.reported = false;
            this.isItACurrentUserStory = isItUserStory;
            this.showThisBubbleWhenCreating = showBubbleOnCreation;
            this.icon.Source = categoryMarkerImage;
            this.categorySource = categoryIconImage;
            this.timeslotSource = timeSlotIconImage;
            this.storytext = storyText.Replace("`", "'");//replaces the tilde (`) with a single quote (')
            this.storytitle = storyTitle.Replace("`", "'");//replaces the tilde (`) with a single quote (')
            this.catdesc = catDesc;
            this.museumImageURL = museumImageUrl;
            this.animate = animateMarkerAppearance;

            this.InitialiseThis();
        }

        private void InitialiseThis()
        {
            this.Unloaded += new RoutedEventHandler(CustomMarker_Unloaded);
            this.Loaded += new RoutedEventHandler(CustomMarker_Loaded);
            this.SizeChanged += new SizeChangedEventHandler(CustomMarker_SizeChanged);
            this.MouseUp += new MouseButtonEventHandler(CustomMarker_MouseUp);
            this.MouseDown += new MouseButtonEventHandler(CustomMarker_MouseDown);
            this.TouchDown += new EventHandler<TouchEventArgs>(CustomMarker_TouchDown);

            this.Name = "Marker";

            NameScope.SetNameScope(this, new NameScope());
            NameScope.GetNameScope(this).RegisterName(this.Name, RenderTransform);

            if (showThisBubbleWhenCreating && MainWindow.readMode)
            {
                showThisBubbleWhenCreating = false;
                this.showMarker();
            }
        }

        void CustomMarker_TouchDown(object sender, TouchEventArgs e)
        {
            MainWindow.touchedMarker = true;//if this touch is not done on a marker
            MainWindow.MainMap.DragButton = MouseButton.Right;
           // e.Handled = true;
        }

        void CustomMarker_Loaded(object sender, RoutedEventArgs e)
        {
            if (icon.Source.CanFreeze)
            {
                this.icon.Source.Freeze();
            }

            //If its a user story, apply different set of effects to 'other' stories
            if (this.isItACurrentUserStory)
            {
                this.shadowEffect = new DropShadowEffect();
                this.shadowEffect.ShadowDepth = 0;
                this.shadowEffect.BlurRadius = 20;
                this.shadowEffect.Color = Colors.White;
                this.icon.Effect = this.shadowEffect;
            }
            else if (animate)
            {
                this.anim.Duration = new TimeSpan(0, 0, 0, 0, 500);
                this.scale.Duration = new Duration(new TimeSpan(0, 0, 0, 0, 100));

                this.anim.From = 0;
                this.anim.To = 1;

                this.scale.From = 0;
                this.scale.To = 1;

                this.oTransform = new ScaleTransform();
                this.oTransform.CenterX = this.Width / 2;
                this.oTransform.CenterY = this.Height;
                this.RenderTransform = oTransform;

                this.oTransform.BeginAnimation(ScaleTransform.ScaleXProperty, scale);
                this.oTransform.BeginAnimation(ScaleTransform.ScaleYProperty, scale);

                this.BeginAnimation(OpacityProperty, anim);
            }

            if (showThisBubbleWhenCreating)
            {
                showThisBubbleWhenCreating = false;
                showMarker();
            }

        }

        void CustomMarker_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            this.Marker.Offset = new Point(-e.NewSize.Width / 2, -e.NewSize.Height);
        }

        void CustomMarker_MouseUp(object sender, MouseEventArgs e)
        {
            //if read mode is active
            if (MainWindow.readMode)
            {
                showMarker();
                e.Handled = true;
            }
        }

        void CustomMarker_MouseDown(object sender, MouseEventArgs e)
        {
            foreach (GMapMarker marker in MainWindow.MainMap.Markers)
            {
                if ((marker.Shape as CustomMarker).thisMarkersPopupIsShowing)
                {
                    (marker.Shape as CustomMarker).hideMarker();
                }
            }
        }

        void defer_Tick(object sender, EventArgs e)
        {
            if(MainWindow == null)//finish
            {
                if (sender != null)
                {
                    (sender as System.Windows.Forms.Timer).Stop();
                    (sender as System.Windows.Forms.Timer).Tick -= new EventHandler(defer_Tick);
                    sender = null;
                }
            }

            else if (!MainWindow.mapIsPanning)
            {
                (sender as System.Windows.Forms.Timer).Stop();
                (sender as System.Windows.Forms.Timer).Tick -= new EventHandler(defer_Tick);
                sender = null;
                if (this.icon != null)
                {
                    this.icon.Visibility = System.Windows.Visibility.Hidden;

                    if (!MainWindow.projectorMode)
                    {
                        MainWindow.idleTimer.Stop();
                    }

                    MainWindow.userIsCurrentlyReadingAStory = true;
                }
            }
        }

        //hides the text bubble
        void storyBubbleLifeTimer_Tick(object sender, EventArgs e)
        {
            if (storyBubbleLifeTimer != null && storyBubbleLifeTimer.Enabled)
            {
                storyBubbleLifeTimer.Stop();
                storyBubbleLifeTimer.Tick -= new EventHandler(storyBubbleLifeTimer_Tick);
                hideMarker();
            }
        }

        /// <summary>
        /// shows the text bubble for projector app
        /// </summary>
        public void ShowMarkerBubble()
        {
            if (!this.thisMarkersPopupIsShowing)
            {
                showThisBubbleWhenCreating = false;
                showMarker();
                if (storyBubbleLifeTimer != null)
                {
                    storyBubbleLifeTimer.Interval = 45000; //20 seconds
                    storyBubbleLifeTimer.Tick += new EventHandler(storyBubbleLifeTimer_Tick);
                    storyBubbleLifeTimer.Start();
                }
            }
        }

        void showMarker()
        {
            this.thisMarkersPopupIsShowing = true;
            
            ///////////////
            GPoint point = MainWindow.MainMap.FromLatLngToLocal(Marker.Position);
            int xTranslate = 0;
            int yTranslate = Convert.ToInt32((MainWindow.readStoryCanvas.Height + MainWindow.readStoryCanvas.Margin.Top - MainWindow.Height) / 2 + 32);

            if(MainWindow.Width == 1280)
            {
                xTranslate = -160;
            }
            else if (MainWindow.Width == 1366)
            {
                xTranslate = -118;
            }
            else if (MainWindow.Width == 1440)
            {
                xTranslate = -82;
            }
            else if (MainWindow.Width == 1680)
            {
                xTranslate = Convert.ToInt32((MainWindow.Width / 2) - ((MainWindow.Width - MainWindow.readStoryCanvas.Width) / 2) - 311);
            }
            else if (MainWindow.Width == 1920)
            {
                xTranslate = Convert.ToInt32((MainWindow.Width / 2) - ((MainWindow.Width - MainWindow.readStoryCanvas.Width) / 2) - 191);
            }
            

            PointLatLng gmapPoint = MainWindow.MainMap.FromLocalToLatLng(point.X + xTranslate, point.Y - yTranslate);  
            MainWindow.panTo(gmapPoint, false, 0);// moves the map center to the position with a smooth pan

            MainWindow.ShowReadStoryCanvas();

            string StoryText = "";
            ///cuts the string short to fit in bubble if it is too big
            if (storytext.Length > 420)
            {
                //Console.WriteLine(title);
                StoryText = storytext.Substring(0, 420) + " ..";
            }
            else
            {
                StoryText = storytext;
            }

            if (MainWindow.readStoryTextBlock.TextDecorations.Count >= 1)
            {
                MainWindow.readStoryTextBlock.TextDecorations.RemoveAt(0);
            }

            if (MainWindow.readStoryTitleTextBlock.TextDecorations.Count >= 1)
            {
                MainWindow.readStoryTitleTextBlock.TextDecorations.RemoveAt(0);
            }

            //MainWindow.button_report.Visibility = Visibility.Visible;
            MainWindow.report_text.Visibility = Visibility.Visible;
            MainWindow.museumImageGrid.Visibility = Visibility.Hidden;

            if (!reported)
            {
                //content
                MainWindow.readStoryTextBlock.TextWrapping = TextWrapping.Wrap;
                MainWindow.readStoryTextBlock.TextAlignment = TextAlignment.Left;
                MainWindow.readStoryTextBlock.Text = StoryText;
                MainWindow.readStoryTextBlock.FontFamily = new FontFamily("Lucida Sans Unicode");
                MainWindow.readStoryTextBlock.IsHitTestVisible = false;
                MainWindow.readStoryTextBlock.Foreground = new SolidColorBrush(Color.FromArgb((byte)0xFF, (byte)0x40, (byte)0x81, (byte)0x9B));
                MainWindow.readStoryTextBlock.FontSize = 24;
                MainWindow.readStoryCategoryImage.Source = categorySource;
                MainWindow.readStoryTimeslotImage.Source = timeslotSource;
                
                //title
                MainWindow.readStoryTitleTextBlock.TextWrapping = TextWrapping.Wrap;
                MainWindow.readStoryTitleTextBlock.TextAlignment = TextAlignment.Left;
                MainWindow.readStoryTitleTextBlock.Text = storytitle.ToUpper();
                MainWindow.readStoryTitleTextBlock.FontFamily = new FontFamily("Lucida Sans Unicode");
                MainWindow.readStoryTitleTextBlock.IsHitTestVisible = false;
                MainWindow.readStoryTitleTextBlock.Foreground = new SolidColorBrush(Color.FromArgb((byte)0xFF, (byte)0x40, (byte)0x81, (byte)0x9B)); //Brushes.Orange;
                MainWindow.readStoryTitleTextBlock.FontSize = 26;

                //cat desc
                MainWindow.categoryDescTextBlock.TextWrapping = TextWrapping.Wrap;
                MainWindow.categoryDescTextBlock.TextAlignment = TextAlignment.Left;
                //MainWindow.categoryDescTextBlock.Text = catdesc;
                MainWindow.categoryDescTextBlock.FontFamily = new FontFamily("Lucida Sans Unicode");
                MainWindow.categoryDescTextBlock.IsHitTestVisible = false;
                MainWindow.categoryDescTextBlock.Foreground = new SolidColorBrush(Color.FromArgb((byte)0xFF, (byte)0xDE, (byte)0x98, (byte)0x27));   //Brushes.White;
                MainWindow.categoryDescTextBlock.FontSize = 16;               
            }

            if (StoryText.Equals(""))  //the marker will give message to inform user that moderation is needed
            {
                //content
                MainWindow.readStoryTextBlock.FontSize = 26;
                //MainWindow.readStoryTextBlock.TextDecorations.Add(TextDecorations.Underline);
                MainWindow.readStoryTextBlock.Foreground = new SolidColorBrush(Color.FromArgb((byte)0xFF, (byte)0x40, (byte)0x81, (byte)0x9B));
                MainWindow.readStoryTextBlock.TextAlignment = TextAlignment.Left;
                MainWindow.readStoryTextBlock.Text = "Your story will need to be moderated before being published";

                //title
                MainWindow.readStoryTitleTextBlock.FontSize = 28;
                MainWindow.readStoryTitleTextBlock.TextDecorations.Add(TextDecorations.Underline);
                MainWindow.readStoryTitleTextBlock.Foreground = new SolidColorBrush(Color.FromArgb((byte)0xFF, (byte)0x40, (byte)0x81, (byte)0x9B));
                MainWindow.readStoryTitleTextBlock.TextAlignment = TextAlignment.Left;
                MainWindow.readStoryTitleTextBlock.Text = "MODERATION PENDING";

                
                MainWindow.report_text.IsEnabled = false;
                MainWindow.report_text.Opacity = 0.2;
            }

            MainWindow.userIsCurrentlyReadingAStory = true;
            this.Marker.ZIndex += 10000;



            ///Museum Image handling
            if (this.museumImageURL != null && !this.museumImageURL.Equals(""))
            {
                MainWindow.report_text.Visibility = Visibility.Hidden;
                if (!museumImageURL.Equals("NONE"))
                {
                    MainWindow.museumImageGrid.Visibility = Visibility.Visible;

                    try
                    {
                        if (museumImage == null)
                        {
                            this.museumImage = new Image();
                            WebClient wcMuseumImage = new WebClient();
                            System.IO.Stream streamMuseumImage = wcMuseumImage.OpenRead(MainWindow.iconsStarterPath + museumImageURL);
                            System.Drawing.Bitmap museumImg = new System.Drawing.Bitmap(streamMuseumImage);
                            this.museumImage.Source = Utility.GetImage(museumImg);
                        }

                        Border border = new Border();
                        border.Height = 200;
                        border.Width = 300;
                        border.BorderBrush = Brushes.Transparent;
                        border.BorderThickness = new Thickness(1, 1, 1, 1);
                        border.CornerRadius = new CornerRadius(8, 8, 8, 8);
                        border.HorizontalAlignment = HorizontalAlignment.Right;
                        border.VerticalAlignment = VerticalAlignment.Top;

                        Grid newGrid = new Grid();

                        Border mask = new Border();
                        mask.Name = "mask";
                        mask.Background = Brushes.White;
                        mask.CornerRadius = new CornerRadius(20, 20, 20, 20);

                        StackPanel panel = new StackPanel();
                        panel.OpacityMask = new VisualBrush(mask);
                        panel.Children.Add(museumImage);

                        newGrid.Children.Add(mask);
                        newGrid.Children.Add(panel);
                        border.Child = newGrid;

                        MainWindow.museumImageGrid.Children.Add(border);
                    }

                    catch
                    {
                        this.museumImage = null;
                    }
                }
            }
        }

        public void hideMarker()
        {
            if (this.Marker != null && this.thisMarkersPopupIsShowing)
            {
                this.Marker.ZIndex -= 10000;
                this.thisMarkersPopupIsShowing = false;
                MainWindow.HideReadStoryCanvas();

                //remove any museum image
                for (int i = 0; i < MainWindow.museumImageGrid.Children.Count; i++)
                {
                    MainWindow.museumImageGrid.Children.RemoveAt(i);
                }
                this.museumImage = null;
            }
        }


        /// <summary>
        /// Its massive but necessary
        /// 
        /// We identified a major memory leak without these 
        /// using ANTS .net Memory Profiler
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void CustomMarker_Unloaded(object sender, RoutedEventArgs e)
        {
            //remove any museum image
            for (int i = 0; i < MainWindow.museumImageGrid.Children.Count; i++)
            {
                MainWindow.museumImageGrid.Children.RemoveAt(i);
            }

            this.Unloaded -= new RoutedEventHandler(CustomMarker_Unloaded);
            this.Loaded -= new RoutedEventHandler(CustomMarker_Loaded);
            this.SizeChanged -= new SizeChangedEventHandler(CustomMarker_SizeChanged);
            this.MouseUp -= new MouseButtonEventHandler(CustomMarker_MouseUp);
            this.MouseDown -= new MouseButtonEventHandler(CustomMarker_MouseDown);
            this.TouchDown -= new EventHandler<TouchEventArgs>(CustomMarker_TouchDown);
            if(storyBubbleLifeTimer != null)
            {
                storyBubbleLifeTimer.Tick -= new EventHandler(storyBubbleLifeTimer_Tick);
            }
            storyBubbleLifeTimer = null;
            this.Marker.Clear();
            this.MainWindow = null;
            this.Marker.Shape = null;
            this.Marker = null;
            this.icon.Effect = null;
            this.icon.Source = null;
            this.icon = null;
            this.categorySource = null;
            this.timeslotSource = null;
            this.scale = null;
            this.anim = null;
            this.museumImage = null;
            
            if (this.shadowEffect != null)
            {
                this.shadowEffect = null;
            }
            if (this.oTransform != null)
            {
                this.oTransform = null;
            }
        }

    }
}